package com.snowy.hidden.user.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.snowy.framework.common.base.vo.LoginUser;
import com.snowy.framework.common.resp.BaseResp;
import com.snowy.framework.common.resp.BaseRespUtil;
import com.snowy.framework.exception.UABPException;
import com.snowy.framework.util.RandomUtil;
import com.snowy.framework.wechatAuth.dto.resp.WechatUserInfo;
import com.snowy.framework.wechatAuth.enums.WechatErroEnum;
import com.snowy.framework.wechatAuth.service.WechatAuthService;
import com.snowy.hidden.constant.AuthErrorENU;
import com.snowy.hidden.constant.RedisConstant;
import com.snowy.hidden.constant.RoleTypeEnum;
import com.snowy.hidden.constant.StatusEnum;
import com.snowy.hidden.user.domain.dto.UserInfoDTO;
import com.snowy.hidden.user.domain.model.SysOrg;
import com.snowy.hidden.user.domain.model.SysUser;
import com.snowy.hidden.user.domain.req.GetWechatPhoneReq;
import com.snowy.hidden.user.domain.req.WechatLoginReq;
import com.snowy.hidden.user.mapper.SysOrgMapper;
import com.snowy.hidden.user.mapper.SysUserMapper;
import com.snowy.hidden.user.service.AppletUserService;
import com.snowy.hidden.user.service.AuthService;
import com.snowy.hidden.user.service.SysRelationService;
import com.snowy.hidden.user.service.SysRoleService;
import com.snowy.hidden.util.CommonCryptogramUtil;
import com.snowy.hidden.util.CustomUtil;
import com.snowy.redis.RedisStaticUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.snowy.framework.wechatAuth.service.WechatAppletService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;


@Slf4j
@Service("authService")
public class AuthServiceImpl implements AuthService {
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysRelationService sysRelationService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private SysOrgMapper sysOrgMapper;
    @Resource
    private WechatAppletService wechatAppletService;
    @Resource
    private AppletUserService appletUserService;
    @Resource
    private WechatAuthService wechatAuthService;

//
//    @Override
//    public void logout(LoginUser sysUser) {
//        this.delRedisUserInfo(sysUser);
//
//    }


    /**
     * 保存用户信息
     *
     * @param sysUser
     * @return
     */
    private SysUser saveRedisUserInfo(SysUser sysUser) {

        String userId = sysUser.getId();
        sysUser.setToken(UUID.randomUUID().toString());
        String token = CustomUtil.toStr(RedisStaticUtil.hget(RedisConstant.LOGIN_REDIS_TOKEN, userId));

        //默认redis有效期30天
        int dayNum = 30;
        if (RedisStaticUtil.getInt("app_token_time") != null) {
            dayNum = RedisStaticUtil.getInt("app_token_time");
        }
        Long longTime = dayNum * 24 * 60 * 60L;
        //验证缓存是否存在，不存在新建，存在替换
        if (token != null && token.length() > 0) {
            //删除历史信息
            RedisStaticUtil.hdel(RedisConstant.LOGIN_REDIS_TOKEN, userId);
            RedisStaticUtil.hdel(RedisConstant.LOGIN_REDIS_USERINFO, token);
            //保存新信息
            RedisStaticUtil.hset(RedisConstant.LOGIN_REDIS_TOKEN, userId, sysUser.getToken(), longTime);
            RedisStaticUtil.hset(RedisConstant.LOGIN_REDIS_USERINFO, sysUser.getToken(), JSONObject.toJSONString(sysUser), longTime);
        } else {
            RedisStaticUtil.hset(RedisConstant.LOGIN_REDIS_TOKEN, userId, sysUser.getToken(), longTime);
            RedisStaticUtil.hset(RedisConstant.LOGIN_REDIS_USERINFO, sysUser.getToken(), JSONObject.toJSONString(sysUser), longTime);
        }
        return sysUser;
    }

//    /**
//     * 删除用户信息
//     *
//     * @param sysUser
//     * @return
//     */
//    private void delRedisUserInfo(LoginUser sysUser) {
//
//        String userId = sysUser.getId().toString();
//        String token = CustomUtil.toStr(RedisStaticUtil.hget(RedisConstant.LOGIN_REDIS_TOKEN, userId));
//        //验证缓存是否存在，不存在新建，存在替换
//        if (token != null && token.length() > 0) {
//            //删除历史信息
//            RedisStaticUtil.hdel(RedisConstant.LOGIN_REDIS_TOKEN, userId);
//            RedisStaticUtil.hdel(RedisConstant.LOGIN_REDIS_USERINFO, token);
//        }
//    }



    @Override
    public UserInfoDTO loginPWDRole(String phoneNumber, String password) {
        //1、验证参数合法
        if (ObjectUtil.hasEmpty(phoneNumber, password)) {
            throw new UABPException(AuthErrorENU.ACCOUNT_PWD_EMPTY.getCode(), AuthErrorENU.ACCOUNT_PWD_EMPTY.getMsg());
        }
        //2、判断用户是否存在
        /**
         * 判断用户是否存在
         */
        Wrapper queryWrapperSys = Wrappers.<SysUser>lambdaQuery().eq(SysUser::getAccount, phoneNumber).eq(SysUser::getUserStatus,"ENABLE");
        SysUser sysUser = sysUserMapper.selectOne(queryWrapperSys);
        if(ObjectUtil.isEmpty(sysUser)){
            throw new UABPException(AuthErrorENU.ACCOUNT_ERROR.getCode(), AuthErrorENU.ACCOUNT_ERROR.getMsg());
        }

        // SM2解密并获得前端传来的密码哈希值
        String passwordHash;
        try {
            // 解密，并做哈希值
            passwordHash = CommonCryptogramUtil.doHashValue(CommonCryptogramUtil.doSm2Decrypt(CommonCryptogramUtil.doSm2Encrypt(password)));
        } catch (Exception e) {
            throw new UABPException(AuthErrorENU.PWD_DECRYPT_ERROR.getCode(), AuthErrorENU.PWD_DECRYPT_ERROR.getMsg());
        }

        //2.2验证账号密码是否正确
        if (!sysUser.getPassword().equals(passwordHash)) {
            throw new UABPException(AuthErrorENU.ACCOUNT_PWD_ERROR.getCode(), AuthErrorENU.ACCOUNT_PWD_ERROR.getMsg());
        }

        // 角色集合
        List<cn.hutool.json.JSONObject> roleList = getRoleList(sysUser.getId());
        if (roleList.isEmpty() ){
            throw new UABPException(AuthErrorENU.VALIDATE_ERR.getCode(), AuthErrorENU.VALIDATE_ERR.getMsg());
        }
        // 角色码集合
        List<String> roleCodeList = roleList.stream().map(jsonObject -> jsonObject.getStr("code")).collect(Collectors.toList());
        if (roleCodeList.isEmpty() ){
            throw new UABPException(AuthErrorENU.VALIDATE_ERR.getCode(), AuthErrorENU.VALIDATE_ERR.getMsg());
        }
        if (!roleCodeList.contains(RoleTypeEnum.basic.getValue())){
            throw new UABPException(AuthErrorENU.ROLE_ERR.getCode(), AuthErrorENU.ROLE_ERR.getMsg());
        }

        //获取人员的单位dept1
        SysOrg sysOrg=sysOrgMapper.selectById(sysUser.getOrgId());
        if (ObjectUtil.isEmpty(sysOrg)){
            throw new UABPException(AuthErrorENU.ORG_ERROR.getCode(), AuthErrorENU.ORG_ERROR.getMsg());
        }


        sysUser.setOrgId(sysOrg.getId());//组织机构
        sysUser.setOrgName(sysOrg.getName());//部门名称

        sysUser = this.saveRedisUserInfo(sysUser);
        UserInfoDTO userInfoDTO=new UserInfoDTO();
        BeanUtils.copyProperties(sysUser,userInfoDTO);
        return userInfoDTO;

    }

//    @Override
//    public LoginUser appletLogin(WechatLoginReq req) {
//        // 获取redis配置的小程序参数
//        String appId = RedisStaticUtil.getStr(RedisConstant.CONFIG_DATA + "wechat_appid");
//        String appKey = RedisStaticUtil.getStr(RedisConstant.CONFIG_DATA + "wechat_appsecret");
//
//        //判断是否配置小程序参数
//        if (StrUtil.hasBlank(appId, appKey)) {
//            throw new UABPException(WechatErroEnum.NO_APPINFO_ERROR);
//        }
//        // 根据微信授权码获取openId
//        WechatUserInfo wechatUserInfo = wechatAppletService.getWechatUserInfo(req.getCode(), appId, appKey);
//        // 从微信获取手机号
//        String phone = wechatAuthService.getPhoneByAuthCode(wechatUserInfo.getAccessToken(), req.getPhoneCode());
//        LoginUser loginUser = this.appletUserService.getByOpenIdAndPhone(wechatUserInfo.getOpenId(),phone);
//        StpUtil.login(loginUser.getUserId());
//        StpUtil.getTokenSession().set("loginUser", loginUser);
//        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
//        loginUser.setTokenName(tokenInfo.getTokenName());
//        loginUser.setTokenValue(tokenInfo.getTokenValue());
//        return loginUser;
//    }

    public List<cn.hutool.json.JSONObject> getRoleList(String userId) {
        List<String> roleIdList = sysRelationService.getRelationTargetIdListByObjectIdAndCategory(userId,
                "SYS_USER_HAS_ROLE");
        if (ObjectUtil.isNotEmpty(roleIdList)) {
            return sysRoleService.listByIds(roleIdList).stream().map(JSONUtil::parseObj).collect(Collectors.toList());
        }
        return CollectionUtil.newArrayList();
    }



    @Override
    public BaseResp loginByWechat(WechatLoginReq wechatLoginReq, HttpServletRequest request) {
        // 获取redis配置的小程序参数
//        String appId = RedisStaticUtil.getStr(RedisConstant.CONFIG_DATA + "wechat_appid");
//        String appKey = RedisStaticUtil.getStr(RedisConstant.CONFIG_DATA + "wechat_appsecret");
        String appId = "wxd1cb8dcfb320ae2a";
        String appKey = "7f6fe2d4c3588eb8a67f443499f5da32";

        //判断是否配置小程序参数
        if (StrUtil.hasBlank(appId, appKey)) {
            throw new UABPException(WechatErroEnum.NO_APPINFO_ERROR);
        }

        WechatUserInfo wechatUserInfo = null;
        //根据授权码取微信基本信息
        try {
            wechatUserInfo = wechatAppletService.getWechatUserInfo(wechatLoginReq.getCode(), appId, appKey);;
        } catch (UABPException e) {
            return BaseRespUtil.Error(e);
        }


        //todo
        String openId = wechatUserInfo.getOpenId();
        String accessToken = wechatUserInfo.getAccessToken();
        //获取用户信息
        LoginUser loginUser = this.appletUserService.getByOpenIdAndPhone(openId,"_");
        StpUtil.login(loginUser.getUserId());
        StpUtil.getTokenSession().set("loginUser", loginUser);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        loginUser.setTokenName(tokenInfo.getTokenName());
        loginUser.setTokenValue(tokenInfo.getTokenValue());
        loginUser.setAccessToken(accessToken);
        loginUser.setOpenId(openId);
        //保持redis
        saveRedisLoginUser(loginUser);
        return BaseRespUtil.Success(loginUser);
    }

    @Override
    public String getWechatPhone(GetWechatPhoneReq getWechatPhoneReq, String accessToken) {
        //1、获取电话
        String phone = wechatAuthService.getPhoneByAuthCode(accessToken, getWechatPhoneReq.getPhoneCode());
        return phone;
    }


    private void saveRedisLoginUser(LoginUser loginUser){
        String userId = loginUser.getUserId();
        String newToken = loginUser.getTokenValue();

        String oldToken = CustomUtil.toStr(RedisStaticUtil.hget(RedisConstant.LOGIN_REDIS_TOKEN, userId));
        Long longTime = 24 * 60 * 60L;
        //验证缓存是否存在，不存在新建，存在替换
        if (StringUtils.isNotBlank(oldToken)) {
            //删除历史信息
            RedisStaticUtil.hdel(RedisConstant.LOGIN_REDIS_TOKEN, userId);
            RedisStaticUtil.del(RedisConstant.LOGIN_REDIS_USERINFO+oldToken);
            //保存新信息
            RedisStaticUtil.hset(RedisConstant.LOGIN_REDIS_TOKEN, userId, newToken);
            RedisStaticUtil.set(RedisConstant.LOGIN_REDIS_USERINFO+newToken, JSONObject.toJSONString(loginUser), longTime);
        } else {
            RedisStaticUtil.hset(RedisConstant.LOGIN_REDIS_TOKEN, userId, newToken);
            RedisStaticUtil.set(RedisConstant.LOGIN_REDIS_USERINFO+newToken, JSONObject.toJSONString(loginUser), longTime);
        }
    }


}
